#include "refuelling.hpp"
#include "csv_struct.hpp"

float refuelling_csv::latest_price(int _plate_id, boost::gregorian::date _date)
{
	float price(0.);
	csv_struct csv_file(file_list::refuelling_filename());
	boost::gregorian::date null_date(boost::gregorian::not_a_date_time), last_date(boost::gregorian::not_a_date_time);

	while(!csv_file.eof())
	{
		++csv_file;
		refuelling_struct_csv r(csv_file.get_line());
			
		if(!check_parm(r, _plate_id, _date))
		{
			continue;
		}		
		
		if(last_date == null_date  || last_date <  r.refuellingDate())
		{
			last_date = r.refuellingDate();
			price = r.unitaryCost();
		}
	}

	//std::cout<< "[refuelling.latest_price] LAST FUEL PRICE IN DATE " << last_date << " = " << price<< " euro/lt" << std::endl;

	return price;
}

bool refuelling_csv::check_parm(refuelling_struct_csv& row, int _plate_id, boost::gregorian::date _date)
{
	if(row.plateId() != _plate_id){ return false;} 		// check plate Id
	if(row.refuellingDate() > _date ){ return false; }      // discard any date after
	
	return true;
}


float refuelling_csv::total_amount(int _plate_id, boost::gregorian::date _first_date, boost::gregorian::date _last_date, bool _include_last_date)
{
	float amount(0.);
	csv_struct csv_file(file_list::refuelling_filename());
		
	while(!csv_file.eof())
	{
		++csv_file;
		refuelling_struct_csv row(csv_file.get_line());

		if(!check_parm(row, _plate_id, _first_date, _last_date, _include_last_date))
		{	
			continue;
		}	
		amount += row.totalAmount();
	}

	return amount;
}

bool refuelling_csv::check_parm(refuelling_struct_csv& row, 
		int _plate_id, boost::gregorian::date _first_date, boost::gregorian::date _last_date, bool _include_last_date)
{
	if(row.plateId() != _plate_id){ return false;} 					// check plate Id
	if(row.refuellingDate() < _first_date) { return false; }                        // discard any date before
	if(row.refuellingDate() > _last_date ){ return false; }                         // discard any date after
	if(row.refuellingDate() == _last_date && !_include_last_date){  return false; } // is the last date to be considered?
		
	return true;
}


float refuelling_csv::total_fuel(int _plate_id, boost::gregorian::date& _first_date, boost::gregorian::date& _last_date, bool _include_last_date)
{
	float liter(0); //, unitary_cost(0), amount(0);
	csv_struct csv_file(file_list::refuelling_filename());

	while(!csv_file.eof())
	{
		++csv_file;
		refuelling_struct_csv row(csv_file.get_line());

		if(!check_parm(row, _plate_id, _first_date, _last_date, _include_last_date))
		{	
			continue;
		}
	
		liter += row.unitaryCost()? (row.totalAmount()/row.unitaryCost()) : 0;
	
		//std::cout << "[refuelling.total_fuel] REFUELLING DATE = " << row.refuellingDate() <<std::endl;
		//std::cout << "[refuelling.total_fuel] LITERS = " << (row.totalAmount()/row.unitaryCost()) << std::endl;
		//std::cout << "[refuelling.total_fuel] TOTAL LITERS = " << liter << std::endl;
		//std::cout << "[refuelling.total_fuel] " << row << std::endl;

	}

	return liter;
}


float refuelling_csv::find_km_in_period(boost::gregorian::date& _first_date, boost::gregorian::date& _last_date, boost::gregorian::date* _period_ref_date, float* _period_ref_km, bool _include_last_date)
{
	float last_km, first_km;

	// refuelling in period
	if(_period_ref_km[LAST_IN_PERIOD] || _period_ref_km[FIRST_IN_PERIOD])
	{
		last_km = _period_ref_km[LAST_IN_PERIOD];
		_last_date = _period_ref_date[LAST_IN_PERIOD];

		//std::cout << "[refuelling_csv::find_km_in_period] LAST DATE (default) = " << _last_date << std::endl;
		//std::cout << "[refuelling_csv::find_km_in_period] LAST KM (default) = " << last_km << std::endl;

		if(_include_last_date && _period_ref_km[FIRST_AFTER_PERIOD]) // include last date as well, whenever possible
		{	
			last_km = _period_ref_km[FIRST_AFTER_PERIOD];
			_last_date = _period_ref_date[FIRST_AFTER_PERIOD];

			//std::cout << "[refuelling_csv::find_km_in_period] LAST DATE = " << _last_date << std::endl;
		}

			
		if(_period_ref_km[LAST_IN_PERIOD] != _period_ref_km[FIRST_IN_PERIOD]) // more than one refuelling
		{
			first_km = _period_ref_km[FIRST_IN_PERIOD];
			_first_date = _period_ref_date[FIRST_IN_PERIOD];

			//std::cout << "[refuelling_csv::find_km_in_period] FIRST DATE = " << _first_date << std::endl;
			//std::cout << "[refuelling_csv::find_km_in_period] FIRST KM = " << first_km << std::endl;

			return last_km - first_km;
		}

		// only one refuel in period, look for an other one outside
		
		if(_period_ref_km[LAST_BEFORE_PERIOD]) // check backwards
		{
			first_km = _period_ref_km[LAST_BEFORE_PERIOD];
			_first_date = _period_ref_date[LAST_BEFORE_PERIOD];

			//std::cout << "[refuelling_csv::find_km_in_period] LAST DATE BEFORE PERIOD = " << _first_date << std::endl;
			//std::cout << "[refuelling_csv::find_km_in_period] LAST BEFORE PERIOD KM = " << first_km << std::endl;

			return last_km - first_km;
		}	
		else if(_period_ref_km[FIRST_AFTER_PERIOD]) // look forward
		{
			first_km = _period_ref_km[FIRST_IN_PERIOD];
			last_km = _period_ref_km[FIRST_AFTER_PERIOD];

			_first_date = _period_ref_date[FIRST_IN_PERIOD];
			_last_date = _period_ref_date[FIRST_AFTER_PERIOD];					

			std::cout << "[refuelling.find_km_in_period] FIRST IN PERIOD date = " << _first_date << " FIRST AFTER PERIOD date = " << _last_date << std::endl;
			std::cout << "[refuelling.find_km_in_period] FIRST IN PERIOD km = " << first_km << " FIRST AFTER PERIOD km = " << last_km << std::endl;

			return last_km - first_km;
		}

		return 0;
	} 

		
	//std::cout << "[refuelling.find_km_in_period] no refuelling in period\n";
	//std::cout << "[refuelling.find_km_in_period] LAST BEFORE PERIOD km = " << _period_ref_km[LAST_BEFORE_PERIOD] << "; FIRST AFTER PERIOD km = " << _period_ref_km[FIRST_AFTER_PERIOD] << std::endl;

	 // no refuelling in period

	if(_period_ref_km[LAST_BEFORE_PERIOD] && _period_ref_km[FIRST_AFTER_PERIOD])
	{
		_first_date = _period_ref_date[LAST_BEFORE_PERIOD];
		_last_date = _period_ref_date[FIRST_AFTER_PERIOD];
			
		//std::cout << "[refuelling.find_km_in_period] LAST BEFORE PERIOD = " << _first_date << "; FIRST AFTER PERIOD = " << _last_date << std::endl;
		//std::cout << "[refuelling.find_km_in_period] LAST BEFORE PERIOD km = " << _period_ref_km[LAST_BEFORE_PERIOD] << "; FIRST AFTER PERIOD km = " << _period_ref_km[FIRST_AFTER_PERIOD] << std::endl;

		return _period_ref_km[FIRST_AFTER_PERIOD] - _period_ref_km[LAST_BEFORE_PERIOD];			
	}

	if(_period_ref_km[LAST_BEFORE_PERIOD] && _period_ref_km[LAST_BEFORE_PERIOD_PRE])
	{
		_first_date = _period_ref_date[LAST_BEFORE_PERIOD_PRE];
		_last_date = _period_ref_date[LAST_BEFORE_PERIOD];
		
		//std::cout << "[refuelling.find_km_in_period] LAST BEFORE PERIOD PRE = " << _first_date << "; LAST BEFORE PERIOD = " << _last_date << std::endl;

		return _period_ref_km[LAST_BEFORE_PERIOD] - _period_ref_km[LAST_BEFORE_PERIOD_PRE];
	}

	if(_period_ref_km[FIRST_AFTER_PERIOD] && _period_ref_km[FIRST_AFTER_PERIOD_POST])
	{
		_first_date = _period_ref_date[FIRST_AFTER_PERIOD_POST];
		_last_date = _period_ref_date[FIRST_AFTER_PERIOD];

		//std::cout << "[refuelling.find_km_in_period] FIRST AFTER PERIOD date = " << _first_date << "; FIRST_AFTER_PERIOD_POST date = " << _last_date << std::endl;

		return _period_ref_km[FIRST_AFTER_PERIOD] - _period_ref_km[FIRST_AFTER_PERIOD_POST];
	}

	return 0;
}



float refuelling_csv::check_km_and_period(int _plate_id, boost::gregorian::date& _first_date, boost::gregorian::date& _last_date, bool _include_last_date)
{
	bool not_yet_in_period(true);
	boost::gregorian::date 	last_date(boost::gregorian::not_a_date_time); 

	float period_ref_km[] =	{ 0., 0., 0., 0., 0., 0. };
	boost::gregorian::date period_ref_date[] = { last_date, last_date, last_date, boost::gregorian::day_clock::local_day(), boost::gregorian::day_clock::local_day(), boost::gregorian::day_clock::local_day() };

	csv_struct csv_file(file_list::refuelling_filename());

	while(!csv_file.eof())
	{
		++csv_file;
		refuelling_struct_csv row(csv_file.get_line());

		if(!row.kilometers()) { continue; }

		if(!check_parm(row, _plate_id, _first_date, _last_date, _include_last_date)) // outside period
                {
			check_outside(_first_date, _last_date, row, period_ref_date, period_ref_km);
			continue;
                 }

		// inside period
		check_inside(_first_date, _last_date, row, period_ref_date, period_ref_km, not_yet_in_period);
	}

	float km = find_km_in_period(_first_date, _last_date, period_ref_date, period_ref_km, _include_last_date);
//	std::cout << "[refuelling_csv::check_km_and_period] KM = " << km << " first date = " << _first_date << " last date = " << _last_date << std::endl;

	return km;
}


bool refuelling_csv::check_inside(boost::gregorian::date& _first_date, boost::gregorian::date& _last_date, refuelling_struct_csv& row, boost::gregorian::date* _reference_date, float* _reference_km, bool& _not_yet_in_period)
{
	boost::gregorian::date null_date(boost::gregorian::not_a_date_time);
	bool is_outside = row.refuellingDate() > _last_date || row.refuellingDate() < _first_date;
		
	if(_not_yet_in_period)
	{
       		_not_yet_in_period = is_outside;
	}
	
	if(is_outside) return false;


	//if(_reference_date[FIRST_IN_PERIOD] == null_date || _reference_date[FIRST_IN_PERIOD] > row.refuellingDate())
	if(!_reference_km[FIRST_IN_PERIOD] || _reference_km[FIRST_IN_PERIOD] > row.kilometers())
	{ 
		_reference_date[FIRST_IN_PERIOD] = row.refuellingDate();
		_reference_km[FIRST_IN_PERIOD] = row.kilometers();

                 //std::cout << "[refuelling.check_inside] FIRST IN PERIOD = "<< _reference_date[FIRST_IN_PERIOD] << std::endl;
                 //std::cout << "[refuelling.check_inside] FIRST IN PERIOD (km) = "<< _reference_km[FIRST_IN_PERIOD] << std::endl;
                        
        }
		
	//if(_reference_date[LAST_IN_PERIOD] == null_date || _reference_date[LAST_IN_PERIOD] < row.refuellingDate())
	//if(_reference_date[LAST_IN_PERIOD] == day_clock::local_day() || _reference_date[LAST_IN_PERIOD] < row.refuellingDate())
	if(!_reference_km[LAST_IN_PERIOD] || _reference_km[LAST_IN_PERIOD] < row.kilometers())
	{
		_reference_date[LAST_IN_PERIOD] = row.refuellingDate();
		_reference_km[LAST_IN_PERIOD] = row.kilometers();

                 //std::cout << "[refuelling.check_inside] LAST IN PERIOD = "<< _reference_date[LAST_IN_PERIOD] << std::endl;
                 //std::cout << "[refuelling.check_inside] LAST IN PERIOD (km) = "<< _reference_km[LAST_IN_PERIOD] << std::endl;
	}

	return true;
}


bool refuelling_csv::check_outside(boost::gregorian::date& _first_date, boost::gregorian::date& _last_date, refuelling_struct_csv& row, boost::gregorian::date* _reference_date, float* _reference_km)
{		
	bool not_in_period = row.refuellingDate() < _first_date || row.refuellingDate() > _last_date;
	boost::gregorian::date date_null(boost::gregorian::not_a_date_time);
		
	if(!not_in_period) return false;

	//if(row.refuellingDate() < _first_date && (_reference_date[LAST_BEFORE_PERIOD] < row.refuellingDate() || _reference_date[LAST_BEFORE_PERIOD] == date_null))
	if(row.refuellingDate() < _first_date && (_reference_km[LAST_BEFORE_PERIOD] < row.kilometers() || !_reference_km[LAST_BEFORE_PERIOD]))
        {
		_reference_date[LAST_BEFORE_PERIOD_PRE] = _reference_date[LAST_BEFORE_PERIOD];
		_reference_date[LAST_BEFORE_PERIOD] =  row.refuellingDate();

                //std::cout << "[refuelling.check_outside] FIRST DATE: "<< _reference_date[LAST_BEFORE_PERIOD] << std::endl;

		_reference_km[LAST_BEFORE_PERIOD_PRE] = _reference_km[LAST_BEFORE_PERIOD];
		_reference_km[LAST_BEFORE_PERIOD] = row.kilometers();

                //std::cout << "[refuelling.check_outside] FIRST km[LAST_BEFORE_PERIOD]: "<< _reference_km[LAST_BEFORE_PERIOD] << std::endl;
        }
        else 
	//if(row.refuellingDate() > _last_date && _reference_date[FIRST_AFTER_PERIOD] > row.refuellingDate())
	if(row.refuellingDate() > _last_date && (_reference_km[FIRST_AFTER_PERIOD] > row.kilometers() || !_reference_km[FIRST_AFTER_PERIOD] || !(_reference_km[FIRST_AFTER_PERIOD_POST] + _reference_km[LAST_BEFORE_PERIOD] + _reference_km[LAST_BEFORE_PERIOD_PRE] + _reference_km[LAST_IN_PERIOD] + _reference_km[FIRST_IN_PERIOD])))
        {
		_reference_date[FIRST_AFTER_PERIOD_POST] = _reference_date[FIRST_AFTER_PERIOD];
		_reference_date[FIRST_AFTER_PERIOD] = row.refuellingDate();

                //std::cout << "[refuelling.check_outside] LAST DATE: "<< _reference_date[FIRST_AFTER_PERIOD] << std::endl;
                //std::cout << "[refuelling.check_outside] LAST DATE POST: "<< _reference_date[FIRST_AFTER_PERIOD_POST] << std::endl;

		_reference_km[FIRST_AFTER_PERIOD_POST] = _reference_km[FIRST_AFTER_PERIOD];
		_reference_km[FIRST_AFTER_PERIOD] = row.kilometers();

                //std::cout << "[refuelling.check_outside] LAST km[FIRST_AFTER_PERIOD]: "<< _reference_km[FIRST_AFTER_PERIOD] << std::endl;
                //std::cout << "[refuelling.check_outside] LAST km[FIRST_AFTER_PERIOD_POST]: "<< _reference_km[FIRST_AFTER_PERIOD_POST] << std::endl;
        }

	return true;
}


float refuelling_csv::mean_fuel_consumption(int _plate_id, boost::gregorian::date _first_date, boost::gregorian::date _last_date, bool _include_last_date) 
{
	float km(check_km_and_period(_plate_id, _first_date, _last_date, _include_last_date));

//	std::cout << "[refuelling.mean_fuel_consumption] KM BETWEEN SUPPLIES = " << km << std::endl;
//	std::cout << "[refuelling.mean_fuel_consumption] FIRST SUPPLY DATE =" << _first_date << std::endl;
//	std::cout << "[refuelling.mean_fuel_consumption] LAST SUPPLY DATE = " <<_last_date << std::endl;

	if(km && _first_date != _last_date)
	{    
			
		float fuel(total_fuel(_plate_id, _first_date, _last_date, false));

//		std::cout << "[refuelling.mean_fuel_consumption] TOTAL FUEL BETWEEN SUPPLIES = " << fuel << std::endl;
//		std::cout << "[refuelling.mean_fuel_consumption] KMs BETWEEN SUPPLIES = " << km << std::endl;
		return (fuel/km);
	}
	return 0;
}

float refuelling_csv::estimated_fuel_consumption(int _plate_id, boost::gregorian::date _date, bool _include_last_date)
{
	return mean_fuel_consumption(_plate_id, _date, _date, _include_last_date);
}


float refuelling_csv::mean_fuel_distance(int _plate_id, boost::gregorian::date _first_date, boost::gregorian::date _last_date, bool _include_last_date)
{
	float mean_consumption(mean_fuel_consumption(_plate_id, _first_date, _last_date, _include_last_date));
		
	mean_consumption = mean_consumption ? 1./mean_consumption : 0;
		
	return mean_consumption;
}
